package com.zhong.util;

import com.google.common.collect.Maps;
import com.zhong.annotation.ParamValidator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 *  参数校验工具
 * @author:zbg on 2018/5/14
 */
@Slf4j
public class ParamValidatorUtils {

    /**
     *  空校验：包括空字符、全空格字符、空指针 （结合ParamValidator注解使用:提示用的字段名字取ParamValidator注解property值）
     *  校验对象的指定字段
     * @param obj          参数对象
     * @param fieldNames  校验的字段
     * @return             异常信息
     */
    public static String validNullAndBlank(Object obj, String... fieldNames) {
        if (obj == null){
            return "参数对象不能为空";
        }
        Class<?> clazz = obj.getClass();
        //1. 获取该类所有field，包括非Object父类
        Map<String, Field> fieldMap = getAllDeclaredFields(clazz);
        //2.遍历所有field
        for(String fieldName : fieldNames){
            Field field = fieldMap.get(fieldName);
            //3.校验field是否存在
            if (field == null){
                log.error("该字段不存在：{}.{}", obj.getClass().getName(), fieldName);
                continue;
            }
            //4.校验field的注解，是否必填项
            ParamValidator amp = field.getAnnotation(ParamValidator.class);
            if (amp != null && amp.required()){
                try {
                    //5.获取该字段的值
                    Method method = clazz.getMethod("get" + StringUtils.capitalize(field.getName()));
                    Object fieldValue = method.invoke(obj);
                    if (fieldValue == null){  //""  == null  --> true
                        return amp.value() + "不能为空";
                    } else if(fieldValue instanceof String && StringUtils.isEmpty((String)fieldValue)){
                        return amp.value() + "不能为空";
                    }
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    log.error("参数空校验异常", e);
                }
            }
        }
        return null;
    }

    /** 获取所有的字段，包括所有父类，除了Object */
    private static Map<String, Field> getAllDeclaredFields(Class<?> clazz){
        Map<String, Field> fieldMap = Maps.newHashMap();
        Class<?> supClazz = clazz;
        while(!"java.lang.Object".equals(supClazz.getName()) && supClazz != null){
            Field[] fields = supClazz.getDeclaredFields();
            for (Field field : fields){
                fieldMap.put(field.getName(), field);
            }
            supClazz = supClazz.getSuperclass();
        }
        return fieldMap;
    }

    /**
     *  空校验：包括空字符、全空格字符、空指针 （结合ParamValidator注解使用:提示用的字段名字取ParamValidator注解property值）
     *  校验对象的所有字段
     * @param obj          参数对象
     * @return             异常信息
     */
    public static String validNullAndBlank(Object obj){
        Class<?> clazz = obj.getClass();
        Map<String, Field> fieldMap = getAllDeclaredFields(clazz);
        if (MapUtils.isNotEmpty(fieldMap)) {
            for (Map.Entry<String, Field> entry : fieldMap.entrySet()) {
                Field field = entry.getValue();
                ParamValidator amp = field.getAnnotation(ParamValidator.class);
                if (amp != null && amp.required()){
                    try {
                        Method method = clazz.getMethod("get" + org.apache.commons.lang3.StringUtils.capitalize(field.getName()));
                        Object fieldValue = method.invoke(obj);
                        if (fieldValue == null){
                            return amp.value() + "不能为空";
                        } else if(fieldValue instanceof String && org.apache.commons.lang3.StringUtils.isEmpty((String)fieldValue)){
                            return amp.value() + "不能为空";
                        }
                    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                        log.error("参数空校验异常: {}", e);
                        return "参数空校验异常";
                    }
                }
            }
        }
        return null;
    }
}
